#include "CTile.h"

#include "CRegionSceneNode.h"
#include "CTriangleSelector.h"

CTile::CTile(CBlockSceneNode *block)
	: Block(block), Position(STilePosition(0,0,0)), Visible(false), Lighting(true),
	Resource(0), TriangleSelector(0), Material(0)
{
}

CTile::~CTile()
{
	if(TriangleSelector)
		TriangleSelector->drop();
}

const matrix4 CTile::getAbsoluteTransformation() const
{
	return Block->getAbsoluteTransformation() * getRelativeTransformation();
}

const matrix4 CTile::getRelativeTransformation() const
{
	matrix4 mat;
	mat.setTranslation(vector3df((f32)Position.X, (f32)Position.Y, (f32)Position.Z));

	/*if(RelativeScale != vector3df(1.f,1.f,1.f))
	{
		matrix4 smat;
		smat.setScale(RelativeScale);
		mat *= smat;
	}*/
	return mat;
}

u8 CTile::getTileSizeType()
{
	if(DFHack::isFloorTerrain(TileType))
		return ETST_FLOOR;
	else if(DFHack::isWallTerrain(TileType))
		return ETST_WALL;
	else if(DFHack::isRampTerrain(TileType) || DFHack::isStairTerrain(TileType))
		return ETST_DYNAMIC;
	return ETST_EMPTY;
}

void CTile::setTileType(u16 tiletype)
{
	// Drop the triangle selector if the tiletype has changed
	if(TriangleSelector && TileType != tiletype)
	{
		TriangleSelector->drop();
		TriangleSelector = 0;
	}

	TileType = tiletype;
	Resource = Block->getRegion()->getResource(tiletype);

	switch(getTileSizeType())
	{
	case ETST_EMPTY:
		Visible = false;
		BoundingBox.reset(0,0,0);
		break;
	case ETST_WALL:
		Visible = true;
	//	BoundingBox.MinEdge = vector3df(0,0,0);
	//	BoundingBox.MaxEdge = vector3df(1,1,1);
		BoundingBox = Resource->Mesh->getBoundingBox();
		Resource->getTransformation().transformBoxEx(BoundingBox);
//		if(!TriangleSelector)
//			TriangleSelector = new CTriangleSelector(this);
		break;
	case ETST_FLOOR:
		Visible = true;
		//BoundingBox.reset(0.1f,0.1f,0.1f);
		BoundingBox = Resource->Mesh->getBoundingBox();
		Resource->getTransformation().transformBoxEx(BoundingBox);
//		if(!TriangleSelector)
//			TriangleSelector = new CTriangleSelector(this);
		break;
	case ETST_DYNAMIC:
		Visible = true;
		if(Resource != 0 && Resource->Mesh != 0)
		{
			BoundingBox = Resource->Mesh->getBoundingBox();
			Resource->getTransformation().transformBoxEx(BoundingBox);
			//TriangleSelector(Block->getSceneManager()->createTriangleSelector(Resource->Mesh, (ISceneNode*)this));
		}
		else
			BoundingBox.reset(0,0,0);
		break;
	}

	TransformedBoundingBox = BoundingBox;
	this->getAbsoluteTransformation().transformBoxEx(TransformedBoundingBox);
}

ITriangleSelector* CTile::getTriangleSelector()
{
	if(TriangleSelector) return TriangleSelector;

	switch(getTileSizeType())
	{
	case ETST_EMPTY:
		break;
	case ETST_WALL:
	case ETST_FLOOR:
	case ETST_DYNAMIC:
			TriangleSelector = new CTriangleSelector(this);
		break;
/*	case ETST_DYNAMIC:
		if(Resource != 0 && Resource->Mesh != 0)
		{
			TriangleSelector = (CTriangleSelector*)Block->getSceneManager()->createTriangleSelector(Resource->Mesh, (ISceneNode*)this);
		}
		break;*/
	}
	return TriangleSelector;
}

const vector3df CTile::getPositionf() const
{
	return vector3df((f32)Position.X, (f32)Position.Y, (f32)Position.Z);
}

const vector3di CTile::getGlobalPosition() const
{
	vector3df pos = Block->getPosition();
	return vector3di((s32)(pos.X + Position.X), (s32)(pos.Y + Position.Y), (s32)(pos.Z + Position.Z));
	//vector3df pos = Block->getPosition() + RelativeTranslation;
	//return vector3di((s32)(RelativeTranslation.X + Block->getPosition().X), (s32)pos.Y, (s32)pos.Z);
}

#define TILE_NORTH_WEST	1
#define TILE_NORTH_EAST	0
#define	TILE_SOUTH_EAST	3
#define	TILE_SOUTH_WEST	2

#define	TILE_NORTH		1
#define	TILE_EAST		0
#define	TILE_SOUTH		3
#define	TILE_WEST		2

#define TILE_WALL(_a)	(_a ? DFHack::isWallTerrain(_a->TileType) : false)
#define TILE_RAMP(_a)	(_a ? DFHack::isRampTerrain(_a->TileType) : false)
#define TILE_FLOOR(_a)	(_a ? DFHack::isFloorTerrain(_a->TileType) : false)
#define TILE_OPEN(_a)	(_a ? DFHack::isOpenTerrain(_a->TileType) : false)

void CTile::updateTile()
{
	CRegionSceneNode *region = Block->getRegion();

	CTile *adj[] = { 0, 0, 0, 0 };
	CTile *cor[] = { 0, 0, 0, 0 };

	if(DFHack::isWallTerrain(TileType))
	{
		vector3di a = this->getGlobalPosition();

		adj[TILE_EAST] = region->getTile(a + vector3di(-1, 0, 0));
		adj[TILE_NORTH] = region->getTile(a + vector3di(0, 0, -1));
		adj[TILE_WEST] = region->getTile(a + vector3di(1, 0, 0));
		adj[TILE_SOUTH] = region->getTile(a + vector3di(0, 0, 1));

		cor[TILE_NORTH_EAST] = region->getTile(a + vector3di(-1,0,-1));
		cor[TILE_NORTH_WEST] = region->getTile(a + vector3di(1,0,-1));
		cor[TILE_SOUTH_WEST] = region->getTile(a + vector3di(1,0,1));
		cor[TILE_SOUTH_EAST] = region->getTile(a + vector3di(-1,0,1));

		s32 wc = 0;
		s32 rc = 0;
		for(s32 i = 0; i < 4; i++)
		{
			if(adj[i])
			{
				if(DFHack::isWallTerrain(adj[i]->TileType))
					wc++;
				else if(DFHack::isRampTerrain(adj[i]->TileType))
					rc++;
			}
		}
		
		if(wc == 1)
		{
			if(TILE_WALL(adj[TILE_WEST]))
				Resource = region->getResource("WALL2_ROUGH_EAST");
			else if(TILE_WALL(adj[TILE_NORTH]))
				Resource = region->getResource("WALL2_ROUGH_SOUTH");
			else if(TILE_WALL(adj[TILE_SOUTH]))
				Resource = region->getResource("WALL2_ROUGH_NORTH");
			else if(TILE_WALL(adj[TILE_EAST]))
				Resource = region->getResource("WALL2_ROUGH_WEST");
		}
		else if(wc == 2 && rc == 0)
		{
			if(TILE_WALL(adj[TILE_WEST]) && TILE_WALL(adj[TILE_NORTH]))
				Resource = region->getResource("WALL1_ROUGH_SOUTH_EAST");
			else if(TILE_WALL(adj[TILE_NORTH]) && TILE_WALL(adj[TILE_EAST]))
				Resource = region->getResource("WALL1_ROUGH_SOUTH_WEST");
			else if(TILE_WALL(adj[TILE_SOUTH]) && TILE_WALL(adj[TILE_EAST]))
				Resource = region->getResource("WALL1_ROUGH_NORTH_WEST");
			else if(TILE_WALL(adj[TILE_WEST]) && TILE_WALL(adj[TILE_SOUTH]))
				Resource = region->getResource("WALL1_ROUGH_NORTH_EAST");
		}
	}
	else if(DFHack::isRampTerrain(TileType))
	{
		
		vector3di a = this->getGlobalPosition();
		adj[TILE_EAST] = region->getTile(a + vector3di(-1, 0, 0));
		adj[TILE_NORTH] = region->getTile(a + vector3di(0, 0, -1));
		adj[TILE_WEST] = region->getTile(a + vector3di(1, 0, 0));
		adj[TILE_SOUTH] = region->getTile(a + vector3di(0, 0, 1));

		cor[TILE_NORTH_EAST] = region->getTile(a + vector3di(-1,0,-1));
		cor[TILE_NORTH_WEST] = region->getTile(a + vector3di(1,0,-1));
		cor[TILE_SOUTH_WEST] = region->getTile(a + vector3di(1,0,1));
		cor[TILE_SOUTH_EAST] = region->getTile(a + vector3di(-1,0,1));

		s32 r = 0;
		s32 c = 0;
		s32 hi = -1;
		for(s32 i = 0; i < 4; i++)
		{
			if(adj[i] && DFHack::isWallTerrain(adj[i]->TileType))
			{
				//hi = hi == -1 ? i : hi;
				hi = i;
				c++;
			}
			else if(adj[i] && DFHack::isRampTerrain(adj[i]->TileType))
				r++;
		}

		s32 r2 = 0;
		s32 c2 = 0;
		s32 ci = -1;
		for(s32 i = 0; i < 4; i++)
		{
			if(cor[i] && DFHack::isWallTerrain(cor[i]->TileType))
			{
				//ci = ci == -1 ? i : ci;
				ci = i;
				c2++;
			}
			else if(cor[i] && DFHack::isRampTerrain(cor[i]->TileType))
				r2++;
		}

		if(r == 4 && TILE_WALL(cor[TILE_NORTH_WEST]) && TILE_WALL(cor[TILE_SOUTH_EAST]) && !TILE_WALL(cor[TILE_SOUTH_WEST]) && !TILE_WALL(cor[TILE_NORTH_EAST]))
		{
			Resource = region->getResource("RAMP2B_NORTH_WEST_SOUTH_EAST");
		}
		else if(r == 4 && TILE_WALL(cor[TILE_NORTH_EAST]) && TILE_WALL(cor[TILE_SOUTH_WEST]) && !TILE_WALL(cor[TILE_SOUTH_EAST]) && !TILE_WALL(cor[TILE_NORTH_WEST]))
		{
			Resource = region->getResource("RAMP2B_NORTH_EAST_SOUTH_WEST");
		}
		else if(c == 1 || (c == 2 && c2 >= 1))
		{
			if(TILE_WALL(adj[TILE_WEST]))
			{
				if(TILE_WALL(adj[TILE_EAST]) && TILE_RAMP(adj[TILE_NORTH]) && TILE_RAMP(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP4B_NORTH_SOUTH");
				}
				else if(TILE_RAMP(adj[TILE_SOUTH]) && TILE_WALL(cor[TILE_SOUTH_EAST]))
				{
					if(TILE_RAMP(adj[TILE_EAST]))
					{
						if(TILE_WALL(adj[TILE_NORTH]))
							Resource = region->getResource("RAMP4A_SOUTH_EAST");
						else
							Resource = region->getResource("RAMP3A_NORTH_EAST");
					}
					else
					{
						Resource = region->getResource("RAMP2_EAST");
					//	Resource = region->getResource("RAMP3A_SOUTH_WEST");
					}
				}
				else if(TILE_RAMP(adj[TILE_NORTH]) && TILE_WALL(cor[TILE_NORTH_EAST]))
				{
					if(TILE_WALL(adj[TILE_SOUTH]))
						Resource = region->getResource("RAMP4A_NORTH_EAST");
					else
						Resource = region->getResource("RAMP3A_SOUTH_EAST_FLIPZ");
				}
				else if(TILE_WALL(adj[TILE_NORTH]))
				{
					Resource = region->getResource("RAMP3_SOUTH_EAST");
				}
				else if(TILE_WALL(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP3_NORTH_EAST");
				}
				else
					Resource = region->getResource("RAMP2_EAST");
			}
			else if(TILE_WALL(adj[TILE_EAST]))
			{
				if(TILE_WALL(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_NORTH]) && TILE_RAMP(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP4B_NORTH_SOUTH");
				}
				else if(TILE_RAMP(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_NORTH]) && TILE_RAMP(adj[TILE_SOUTH]) && TILE_WALL(cor[TILE_NORTH_WEST]) && TILE_WALL(cor[TILE_SOUTH_WEST]))
				{
					Resource = region->getResource("RAMP4C_WEST");
				}
				else if(TILE_RAMP(adj[TILE_NORTH]) && TILE_WALL(cor[TILE_NORTH_WEST]))
				{
					if(TILE_RAMP(adj[TILE_SOUTH]))
						Resource = region->getResource("RAMP3A_SOUTH_WEST");
					else
						Resource = region->getResource("RAMP4A_NORTH_WEST");
				}
				else if(TILE_RAMP(adj[TILE_SOUTH]) && TILE_WALL(cor[TILE_SOUTH_WEST]))
				{
					if(TILE_WALL(adj[TILE_NORTH]))
						Resource = region->getResource("RAMP4A_SOUTH_WEST");
					else
						Resource = region->getResource("RAMP3A_NORTH_WEST_FLIPZ");
				}
				else if(TILE_WALL(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP3_NORTH_WEST");
				}
				else if(TILE_WALL(adj[TILE_NORTH]))
				{
					Resource = region->getResource("RAMP3_SOUTH_WEST");
				}
				else
					Resource = region->getResource("RAMP2_WEST");
			}
			else if(TILE_WALL(adj[TILE_NORTH]))
			{
				if(TILE_WALL(adj[TILE_SOUTH]) && TILE_RAMP(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_EAST]))
				{
					Resource = region->getResource("RAMP4B_EAST_WEST");
				}
				else if(TILE_RAMP(adj[TILE_EAST]) && TILE_WALL(cor[TILE_SOUTH_EAST]))
				{
					Resource = region->getResource("RAMP3A_SOUTH_WEST_FLIPZ");
				}
				else if(TILE_RAMP(adj[TILE_EAST]) && TILE_WALL(cor[TILE_SOUTH_WEST]))
				{
					Resource = region->getResource("RAMP3A_SOUTH_EAST");
				}
				else if(TILE_RAMP(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP2_SOUTH");
				}
				else
					Resource = region->getResource("RAMP2_SOUTH");
			}
			else if(TILE_WALL(adj[TILE_SOUTH]))
			{
				if(TILE_WALL(adj[TILE_NORTH]) && TILE_RAMP(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_EAST]))
				{
					Resource = region->getResource("RAMP4B_EAST_WEST");
				}
				else if(TILE_RAMP(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_NORTH]) && TILE_RAMP(adj[TILE_EAST]) && TILE_WALL(cor[TILE_NORTH_WEST]) && TILE_WALL(cor[TILE_NORTH_EAST]))
				{
					Resource = region->getResource("RAMP4C_NORTH");
				}
				else if(TILE_RAMP(adj[TILE_WEST]) && TILE_WALL(cor[TILE_NORTH_EAST]))
				{
					Resource = region->getResource("RAMP3A_NORTH_WEST");
				}
				else if(TILE_RAMP(adj[TILE_WEST]) && TILE_WALL(cor[TILE_NORTH_WEST]))
				{
					if(TILE_WALL(adj[TILE_EAST]))
						Resource = region->getResource("RAMP4A_NORTH_EAST");
					else
						Resource = region->getResource("RAMP3A_NORTH_EAST_FLIPZ");
				}
				else if(TILE_RAMP(adj[TILE_WEST]) && TILE_WALL(cor[TILE_SOUTH_EAST]))
				{
					if(TILE_WALL(cor[TILE_NORTH_WEST]))
						Resource = region->getResource("RAMP3A_NORTH_EAST_FLIPZ");
					else if(TILE_RAMP(adj[TILE_EAST]))
						Resource = region->getResource("RAMP2_NORTH");
					else if(TILE_WALL(adj[TILE_EAST]))
						Resource = region->getResource("RAMP3A_NORTH_WEST_FLIPZ");
					else
						Resource = region->getResource("RAMP2_NORTH");
				}
	/*			if(TILE_RAMP(adj[TILE_NORTH]))
				{
					Resource = region->getResource("RAMP3A_SOUTH");
				}
				else if(TILE_RAMP(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP2_NORTH");
				}*/
				else
					Resource = region->getResource("RAMP2_NORTH");
			}
		}
/*		else if(c == 2 && ci == -1)
		{
			switch(hi)
			{
//			case 0:
//				Resource = region->getResource("RAMP1_EAST");
//				break;
			case 1:
				Resource = region->getResource("RAMP1_NORTH");
				break;
//			case 2:
//				Resource = region->getResource("RAMP1_WEST");
//				break;
//			case 3:
//				Resource = region->getResource("RAMP1_SOUTH");
//				break;
			}
		}*/
		else if(c == 2 && ci >= 0)
		{
			if(TILE_WALL(adj[TILE_WEST]))
			{
				if(TILE_WALL(adj[TILE_NORTH]))
				{
					Resource = region->getResource("RAMP3_SOUTH_EAST");
				}
				else if(TILE_WALL(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP3_NORTH_EAST");
				}
			}
			else if(TILE_WALL(adj[TILE_EAST]))
			{
				if(TILE_WALL(adj[TILE_NORTH]))
				{
					Resource = region->getResource("RAMP3_SOUTH_WEST");
				}
				else if(TILE_WALL(adj[TILE_SOUTH]))
				{
					Resource = region->getResource("RAMP3_NORTH_WEST");
				}
			}
		}
		else if(c == 0 && c2 == 1)
		{
			switch(ci)
			{
			case 0:
				Resource = region->getResource("RAMP1_SOUTH_EAST");
				break;
			case 1:
				Resource = region->getResource("RAMP1_NORTH_EAST");
				break;
			case 2:
				Resource = region->getResource("RAMP1_NORTH_WEST");
				break;
			case 3:
				Resource = region->getResource("RAMP1_SOUTH_WEST");
				break;
			}
		}
		else if(c == 0)
		{
			if(TILE_WALL(cor[TILE_NORTH_WEST]) && TILE_WALL(cor[TILE_NORTH_EAST]) && TILE_RAMP(adj[TILE_NORTH]))
			{
				if(TILE_WALL(cor[TILE_SOUTH_EAST]))
				{
					if(TILE_RAMP(adj[TILE_EAST]))
					{
						if(TILE_RAMP(adj[TILE_WEST]) && TILE_RAMP(adj[TILE_SOUTH]))
							Resource = region->getResource("RAMP4D");
						else
							Resource = region->getResource("RAMP3B_SOUTH_WEST");
					}
					else
						Resource = region->getResource("RAMP3A_SOUTH_WEST");
				}
				else
					Resource = region->getResource("RAMP2A_SOUTH");
			}
			else if(TILE_WALL(cor[TILE_NORTH_WEST]) && TILE_WALL(cor[TILE_SOUTH_WEST]) && TILE_RAMP(adj[TILE_WEST]))
			{
				Resource = region->getResource("RAMP2A_EAST");
			}
			else if(TILE_WALL(cor[TILE_NORTH_EAST]) && TILE_WALL(cor[TILE_SOUTH_EAST]) && TILE_RAMP(adj[TILE_EAST]))
			{
				Resource = region->getResource("RAMP2A_WEST");
			}
			else if(TILE_WALL(cor[TILE_SOUTH_WEST]) && TILE_WALL(cor[TILE_SOUTH_EAST]) && TILE_RAMP(adj[TILE_SOUTH]))
			{
				Resource = region->getResource("RAMP2A_NORTH");
			}
		}
		else if(c == 3)
		{
			if(TILE_RAMP(adj[TILE_NORTH]))
			{
				Resource = region->getResource("RAMP4_NORTH");
			}
			else if(TILE_RAMP(adj[TILE_SOUTH]))
			{
				Resource = region->getResource("RAMP4_SOUTH");
			}
			else if(TILE_RAMP(adj[TILE_WEST]))
			{
				Resource = region->getResource("RAMP4_WEST");
			}
			else if(TILE_RAMP(adj[TILE_EAST]))
			{
				Resource = region->getResource("RAMP4_EAST");
			}
		}
		else
		{
		}
	}
}

const DFHack::TileMaterial CTile::getTileMaterial() const
{
	return DFHack::tileTypeTable[TileType].m;
}

const DFHack::TileVariant CTile::getTileVariant() const
{
	return DFHack::tileTypeTable[TileType].v;
}

const DFHack::TileClass CTile::getTileClass() const
{
	return DFHack::tileTypeTable[TileType].c;
}

void CTile::setMaterialIndex(u32 materialindex)
{
//	MaterialIndex = materialindex;
}

SBasicMaterial* CTile::getMaterial() const
{
	//return Block->getRegion()->getInorganicMaterial(this->MaterialIndex);
	return Material;
}